#问题：asyncio的原理是什么？
'''
asyncio 的编程模型就是一个事件循环（event loop），让你可以“在 A 发生时，执行 B”，
以此来实现并发。事件循环的思想是连续监视各种资源的状态（例如，网络连接和数据库查询），
并在事件发生时（例如，当资源准备好或计时器到期时）触发回调函数的执行。asyncio 主要有一个事件循环作为任务调度器，
然后可以用async def定义异步函数作为任务逻辑，通过create_task接口把任务挂到 event loop 上。
event loop 的运行过程应该是个不停循环的过程，不停查看等待类别有没有可以执行的任务，如果有的话执行任务，
直到碰到await之类的主动让出 event loop 的函数，如此反复。
'''

while True:
    # 启动一个事件循环
    for task in tasks:
        if task.done(): # 检查资源的状态
            task.callback()
            tasks.remove(task)
    if len(tasks) == 0:
        # 如果没有任何任务，终止事件循环
        break

#问题：同步编程和异步编程的区别
'''
异步函数中，当每个任务到达等待asyncio.sleep(1)时，count函数都会对事件循环进行控制，暂定1秒钟，但是其他部分继续
异步编程与同步编程的差异所在是同步每次都要等待上一次调用返回结果才能开始新的轮询。
'''

#从一个事例来看看同步编程和异步编程的区别。
#异步版实现(asyncio_count.py)：

import asyncio
from datetime import datetime

async def count(number): # async def定义一个协程函数，返回协程对象
    print("One - ", number, datetime.now().strftime("%H:%M:%S"))

     # 非阻塞调用，这里可以替换为一些耗时的非阻塞IO操作。这里在等待一个将来的结果，
     # 那么与此同时，可以进行其它的一些运算，而count函数就暂停在这里，直到asyncio.sleep返回结果
     # await为事件循环提供断点，以便在等待资源时，事件循环可以继续进行并同时管理其他协程。
    await asyncio.sleep(1)

    print("Two - ", number, datetime.now().strftime("%H:%M:%S"))

async def main():
    # await asyncio.gather(count(1), count(2), count(3)) # asyncio.gather并发运行可等待对象
    task1 = asyncio.create_task(count(1)) # create_task定义asyncio任务，协程对象会自动排入日程，并发运行多个协程对象
    task2 = asyncio.create_task(count(2))
    task3 = asyncio.create_task(count(3))

    await task1
    await task2
    await task3

if __name__ == "__main__":
    import time
    s = time.perf_counter()
    asyncio.run(main()) # asyncio.run函数运行传入的协程，它是asyncio程序的主入口点
    elapsed = time.perf_counter() - s
    print(f"{__file__} executed in {elapsed:0.2f} seconds.")


#同步版实现（sync_count.py）：
import time
from datetime import datetime

def count(number):
    print("One - ", number, datetime.now().strftime("%H:%M:%S"))
    time.sleep(1) # 阻塞调用，无法切换做其它事情
    print("Two - ", number, datetime.now().strftime("%H:%M:%S"))

def main():
    for i in range(3):
        count(i)

if __name__ == "__main__":
    s = time.perf_counter()
    main()
    elapsed = time.perf_counter() - s
    print(f"{__file__} executed in {elapsed:0.2f} seconds.")


